package com.zyx.camunda.common.utils;

import cn.hutool.core.collection.CollectionUtil;
import com.zyx.camunda.model.dto.FlowPath;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.model.bpmn.instance.Process;
import org.camunda.bpm.model.bpmn.instance.*;
import org.camunda.bpm.model.bpmn.instance.camunda.CamundaProperties;
import org.camunda.bpm.model.bpmn.instance.camunda.CamundaProperty;

import java.util.Collection;
import java.util.List;

/**
 * <p>https://docs.camunda.org/manual/7.17/user-guide/model-api/bpmn-model-api/create-a-model/
 *
 * @author Yaxi.Zhang
 * @since 2022/9/21 00:52
 */
@Slf4j
public class BpmnModelUtil {

    public static <T extends BpmnModelElementInstance> T createElement(BpmnModelElementInstance parentElement, String id, Class<T> elementClass) {
        T element = parentElement.getModelInstance().newInstance(elementClass);
        element.setAttributeValue("id", id, true);
        element.getDomElement().registerNamespace("bpmn", "http://www.omg.org/spec/BPMN/20100524/MODEL");
        System.out.println("element.getDomElement().lookupPrefix(\"bpmn\") = " + element.getDomElement().lookupPrefix("bpmn"));
        parentElement.addChildElement(element);
        return element;
    }

    public static SequenceFlow createSequenceFlow(Process process, FlowNode from, FlowNode to) {
        String identifier = from.getId() + "-" + to.getId();
        SequenceFlow sequenceFlow = createElement(process, identifier, SequenceFlow.class);
        process.addChildElement(sequenceFlow);
        sequenceFlow.setSource(from);
        from.getOutgoing().add(sequenceFlow);
        sequenceFlow.setTarget(to);
        to.getIncoming().add(sequenceFlow);
        return sequenceFlow;
    }

    public static void calcFlowPath(FlowNode flowNode, FlowPath previewFlowPath, List<FlowPath> flowPaths) {
        Collection<SequenceFlow> outgoing = flowNode.getOutgoing();
        ExtensionElements extensionElements = flowNode.getExtensionElements();
        if (extensionElements != null) {
            Collection<CamundaProperties> types = extensionElements.getChildElementsByType(CamundaProperties.class);
            log.info("==========>>>>>>>>>> {}", types);
            for (CamundaProperties prop : types) {
                Collection<CamundaProperty> camundaProperties = prop.getCamundaProperties();
                for (CamundaProperty cprop : camundaProperties) {
                    String camundaName = cprop.getCamundaName();
                    String camundaValue = cprop.getCamundaValue();
                    log.info("==========>>>>>>>>>> {}: {}", camundaName, camundaValue);
                }
            }
        }

        // 判断是否有多实例任务
        Collection<MultiInstanceLoopCharacteristics> miLoop = flowNode
                .getChildElementsByType(MultiInstanceLoopCharacteristics.class);
        if (CollectionUtil.isNotEmpty(miLoop)) {
            log.info("==========>>>>>>>>>> {} 节点有多实例任务", flowNode.getName());
        }

        int outSize = outgoing == null ? 0 : outgoing.size();
        if (outSize == 0) {
            flowPaths.add(previewFlowPath);
            return;
        }

        for (SequenceFlow sequenceFlow : outgoing) {
            FlowPath thisFlowPath = new FlowPath(previewFlowPath);
            ConditionExpression conditionExpression = sequenceFlow.getConditionExpression();
            FlowNode nextFlowNode = sequenceFlow.getTarget();
            if (thisFlowPath.getFlowPath().stream().anyMatch(o -> o.getId().equals(nextFlowNode.getId()))) {
                continue;
            }
            if (conditionExpression != null) {
                thisFlowPath.getConditions().add(conditionExpression.getTextContent());
            }
            thisFlowPath.getFlowPath().add(nextFlowNode);
            if (nextFlowNode != null) {
                calcFlowPath(nextFlowNode, thisFlowPath, flowPaths);
            }
        }
    }

}
